home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Power 1997 December
/
MACPOWER-1997-12.ISO.7z
/
MACPOWER-1997-12.ISO
/
AMUG
/
PROGRAMMING
/
Raven 1.2.sit
/
Raven 1.2
/
Source
/
Foundation
/
Common
/
ZAllocator.cpp
< prev
next >
Wrap
Text File
|
1997-07-27
|
9KB
|
332 lines
/*
* File: ZAllocator.cpp
* Summary: Abstract base class for dynamic memory allocators.
* Written by: Jesse Jones
*
* Copyright ゥ 1997 Jesse Jones.
* For conditions of distribution and use, see copyright notice in ZTypes.h
*
* Change History (most recent first):
*
* <2> 5/29/97 JDJ No longer depends on ZMiscUtils.
* <1> 1/29/97 JDJ Created
*/
#include <ZAllocator.h>
#include <ZExceptions.h>
#include <ZFixedAllocator.h>
#include <ZMemUtils.h>
#if DEBUG
#include <Limits.h>
#include <List.h>
#include <Timer.h>
#include <TypeInfo>
#include <ZNumbers.h>
#endif
//-----------------------------------
// Types
//
#if DEBUG
struct STestBlock {
void* ptr;
long deleteCount;
MilliSecond createTime;
STestBlock() {ptr = nil;}
STestBlock(void* p, long count, MilliSecond time) {ptr = p; deleteCount = count; createTime = time;}
bool operator==(const STestBlock& rhs) const {return ptr == rhs.ptr;}
bool operator<(const STestBlock& rhs) const {return ptr < rhs.ptr;}
// These should not be neccesary.
};
typedef list<STestBlock, allocator<STestBlock> > TestList;
// ===================================================================================
// Internal Functions
// ===================================================================================
//---------------------------------------------------------------
//
// GetMilliSecs
//
//---------------------------------------------------------------
static MilliSecond GetMilliSecs()
{
UnsignedWide microSeconds;
Microseconds(µSeconds);
MilliSecond seconds = (MilliSecond) (microSeconds.hi*4294967L + microSeconds.lo/1000); // 4294967L = 2^32 / 1000
return seconds;
}
#pragma mark -
// ===================================================================================
// class ZSizeDistribution
// ===================================================================================
class ZSizeDistribution {
public:
ZSizeDistribution(long maxDelay) {mMaxDelay = maxDelay;}
virtual ulong GetBytes() const = 0;
virtual long GetDelay() const {return 1 + Random(mMaxDelay);}
protected:
long mMaxDelay;
};
// ===================================================================================
// class ZRandomDistribution
// ===================================================================================
class ZRandomDistribution : public ZSizeDistribution {
public:
ZRandomDistribution(long min, long max, long maxDelay) : ZSizeDistribution(maxDelay) {mMin = min; mMax = max;}
virtual ulong GetBytes() const {return (ulong) Random(mMin, mMax);}
// Uniform distribution from min to max.
protected:
long mMin;
long mMax;
};
// ===================================================================================
// class ZPowerDistribution
// ===================================================================================
class ZPowerDistribution : public ZSizeDistribution {
public:
ZPowerDistribution(long maxDelay) : ZSizeDistribution(maxDelay) {}
virtual ulong GetBytes() const;
// 0.5 chance of returning min, 0.25 chance of returning 2*min,
// 0.125 chance of returning 4*min, etc
};
//---------------------------------------------------------------
//
// ZPowerDistribution::GetBytes
//
//---------------------------------------------------------------
ulong ZPowerDistribution::GetBytes() const
{
ulong bytes = 8;
while (FlipCoin() && bytes <= 4*1024L) // limit max block since huge blocks will throw our timings off
bytes = 2*bytes;
return bytes;
}
#pragma mark -
// ===================================================================================
// class ZSelectedDistribution
// ===================================================================================
class ZSelectedDistribution : public ZSizeDistribution {
public:
ZSelectedDistribution(long maxDelay) : ZSizeDistribution(maxDelay) {}
virtual ulong GetBytes() const;
// Uniform distribution of some likely values.
};
//---------------------------------------------------------------
//
// ZSelectedDistribution::GetBytes
//
//---------------------------------------------------------------
ulong ZSelectedDistribution::GetBytes() const
{
static ulong sizes[18] = {8, 12, 14, 16, 18, 20, 30, 40, 50, 60, 70, 80, 90, 100, 150, 200, 250, 500};
long index = Random(18);
ulong bytes = sizes[index];
return bytes;
}
#endif // DEBUG
#pragma mark -
// ===================================================================================
// class TAllocator
// ===================================================================================
//---------------------------------------------------------------
//
// TAllocator::~TAllocator
//
//---------------------------------------------------------------
TAllocator::~TAllocator()
{
}
//---------------------------------------------------------------
//
// TAllocator::TAllocator
//
//---------------------------------------------------------------
TAllocator::TAllocator()
{
}
//---------------------------------------------------------------
//
// TAllocator::operator new [static]
//
//---------------------------------------------------------------
void* TAllocator::operator new(size_t size)
{
ASSERT(size >= sizeof(TAllocator)); // this will be used by subclasses
void* ptr = NewPtr(size);
ThrowIfNil(ptr);
return ptr;
}
//---------------------------------------------------------------
//
// TAllocator::operator delete [static]
//
//---------------------------------------------------------------
void TAllocator::operator delete(void* ptr)
{
if (ptr != nil)
DisposePtr((Ptr) ptr);
}
//---------------------------------------------------------------
//
// TAllocator::DoTest [static]
//
//---------------------------------------------------------------
#if DEBUG
void TAllocator::DoTest(TAllocator& heap, const ZSizeDistribution& distribution)
{
TestList blocks;
ulong count = 0;
MilliSecond minTime = LONG_MAX;
MilliSecond avgTime = 0;
MilliSecond maxTime = LONG_MIN;
MilliSecond time;
TRACE("max avg min¥n");
for (ulong i = 0; i < 16; i++) {
for (ulong j = 0; j < 1000; j++) {
// Delete the blocks that are marked for termination.
TestList::iterator iter = blocks.begin();
while (iter != blocks.end()) {
TestList::iterator pos = iter;
STestBlock block = *iter++;
if (block.deleteCount <= count) {
time = GetMilliSecs();
heap.Deallocate(block.ptr);
time = block.createTime + (GetMilliSecs() - time);
if (time < minTime)
minTime = time;
if (time > maxTime)
maxTime = time;
avgTime += time;
blocks.erase(pos);
}
}
// Create a new block
ulong bytes = distribution.GetBytes();
long delay = distribution.GetDelay();
time = GetMilliSecs();
void* ptr = heap.Allocate(bytes);
time = GetMilliSecs() - time;
ASSERT(ptr != nil);
STestBlock block(ptr, (long) (count + delay), time);
blocks.push_back(block);
count++;
}
TRACE("%-5d %-5d %-5d¥n", maxTime, (avgTime/count), minTime);
}
// Delete remaining blocks so TSimpleAllocator dtor doesn't ASSERT.
TestList::iterator iter = blocks.begin();
while (iter != blocks.end()) {
STestBlock block = *iter++;
heap.Deallocate(block.ptr);
}
TRACE("heap is %dK.¥n¥n", heap.GetHeapSize()/1024);
}
#endif
//---------------------------------------------------------------
//
// TAllocator::TestAllocator [static]
//
// Tests are from Knuth, _The Art of Programming_ vol 1.
// Tests were run on an 8500/120
//
// TSimpleAllocator times:
// uniform 3 2 2 2 (191K)
// power of two 2 3 3 2 (95K)
// selected vals 3 4 4 4 (95K)
//
// TBestFitAllocator times:
// uniform 2 3 2 4 (63K)
// power of two 4 3 2 2 (63K)
// selected vals 2 2 3 3 (63K)
//
//---------------------------------------------------------------
#if DEBUG
void TAllocator::TestAllocator(TAllocator& heap1, TAllocator& heap2, TAllocator& heap3)
{
TRACE("%s allocator times¥n", typeid(heap1).name());
const long kDelay = 1000; // maximum number of iterations a block will hang around
TRACE("Uniform distribution in [16, 500]¥n");
TAllocator::DoTest(heap1, ZRandomDistribution(16, 500, kDelay));
TRACE("Weighted power of 2 distribution¥n");
TAllocator::DoTest(heap2, ZPowerDistribution(kDelay));
TRACE("Uniform distribution of selected values¥n");
TAllocator::DoTest(heap3, ZSelectedDistribution(kDelay));
TRACE("Completed allocator test.¥n¥n");
}
#endif